home *** CD-ROM | disk | FTP | other *** search
/ Ian & Stuart's Australian Mac 1993 September / September 93.iso / Archives / Sound / MIDI / MIDI Utilities / CMU Midi Toolkit / Source / cmdline.c < prev    next >
Text File  |  1988-01-11  |  11KB  |  377 lines

  1. /* cmdline.c -- command line parsing routines
  2.  *
  3.  * this module is designed to allow various modules to scan (and rescan)
  4.  * the command line for applicable arguments.  the goal is to hide as
  5.  * much information about switches and their names as possible so that
  6.  * switches become more consistent across applications and so that the
  7.  * author of an application need not do a lot of work to provide numerous
  8.  * options.  instead, each module scans the command line for its own
  9.  * arguments.
  10.  *
  11.  * command lines are of the following form:
  12.  *        command -s1 -s2 opt2 -s3 arg1 arg2 -s4 opt4 arg3
  13.  *
  14.  * note that there are three kinds of command line parameters:
  15.  *        (1) a switch is a "-" followed by a name, e.g. "-s1"
  16.  *        (2) an option is a switch followed by a space and name, e.g. "-s2 opt2"
  17.  *        (3) an argument is a name by itself, e.g. "arg1"
  18.  *
  19.  * note also that a switch followed by an argument looks just like an
  20.  * option, so a list of valid option names is necessary to disambiguate.
  21.  *
  22.  * a main program that uses cmdline.c should do the following:
  23.  *    (1) create an array of pointers to strings (char *names[]) that
  24.  *        contains every possible option name
  25.  *    (2) create another array of pointers to strings that contains
  26.  *        every possible switch name
  27.  *    (2) call cl_init(switches, nsw, options, nopt, argv, argc)
  28.  *
  29.  * cl_init will report an error (to stderr) if it finds any illegal
  30.  * switch or option names.
  31.  *
  32.  * afterward, switches, options, and arguments can be accessed by
  33.  * calling cl_switch, cl_option, and cl_arg.  if cl_switch or cl_option
  34.  * is called with a switch name that was not mentioned in the call to
  35.  * cl_init, an error will result.  this indicates that the application
  36.  * author omitted a valid switch or option name when calling cl_init.
  37.  * this is an error because the full set of names is needed for error
  38.  * checking and to distinguish arguments from options.
  39.  *
  40.  * cl_nswitch and cl_noption are similar to cl_switch and cl_option,
  41.  * except they each take a list of equivalent switch or option names.
  42.  * this makes it simple to allow both verbose (-debug) and terse (-d) names.
  43.  */
  44.  
  45. /*****************************************************************************
  46. *        Change Log
  47. *  Date        | Change
  48. *-----------+-----------------------------------------------------------------
  49. * 13-Jun-86 | Created Change Log
  50. *  9-Oct-86 | JMaloney: Modified for Macintosh
  51. *  7-Jan-87 | JMaloney: Converted to Lightspeed C
  52. *****************************************************************************/
  53.  
  54. #include "switches.h"
  55.  
  56. #ifdef LIGHTSPEED
  57. #include "Proto.h"
  58. #include <StdIO.h>
  59. #include <Strings.h>
  60. #endif
  61.  
  62. #ifdef MPW
  63. #include <StdIO.h>
  64. #include <Strings.h>
  65. #endif
  66.  
  67. #include "cext.h"
  68. #include "cmdline.h"
  69.  
  70. /*****************************************************************************
  71. *
  72. *    variables private to this module
  73. *
  74. *****************************************************************************/
  75.  
  76. private char **voptions;    /* valid options */
  77. private int noptions;        /* number of options */
  78. private char **vswitches;    /* valid switches */
  79. private int nswitches;        /* number of switches */
  80. private char **argv;        /* command line argument vector */
  81. private int argc;            /* length of argv */
  82. private boolean cl_rdy = false;
  83.                             /* set to true when initialized */
  84.  
  85. /*****************************************************************************
  86. *
  87. *    routines private to this module
  88. *
  89. *****************************************************************************/
  90.  
  91. void    cl_check_names(char *names[], int nnames, char *valid[], int nvalid);
  92. int        cl_find_match(char *names[],int nnames);
  93. int        cl_find_string(char *s, char *names[],int nnames);
  94. void    cl_ready_check(void);
  95.  
  96. /*****************************************************************************
  97. *            cl_check_names
  98. * Inputs:
  99. *    char *names[]: array of alternative switch or option names
  100. *    int nnames: number of alternative switch or option names
  101. *    char *valid[]: array of valid names
  102. *    int nvalid: number of valid names
  103. * Effect:
  104. *    checks that all names are in validnames
  105. *    if not, print an error message
  106. *****************************************************************************/
  107.  
  108. private void cl_check_names(names, nnames, valid, nvalid)
  109.     char *names[];
  110.     int nnames;
  111.     char *valid[];
  112.     int nvalid;
  113. {
  114.     int i;
  115.  
  116.     for (i = 0; i < nnames; i++) {
  117.         if (cl_find_string(names[i], valid, nvalid) >= nvalid) {
  118.             fprintf(stderr, "internal error detected by cmdline module:\n");
  119.             fprintf(stderr, "\t'%s' should be in valid lists\n", names[i]);
  120.         }
  121.     }
  122. }
  123.  
  124. /*****************************************************************************
  125. *            cl_arg
  126. * Inputs:
  127. *    int n: the index of the arg needed
  128. * Results:
  129. *    pointer to the nth arg, or NULL if none exists
  130. *    arg 0 is the command name
  131. *****************************************************************************/
  132.  
  133. public char *cl_arg(n)
  134.     int n;
  135. {
  136.     int i = 1;
  137.  
  138.     if (n <= 0) return argv[0];
  139.     while (i < argc) {
  140.         if (*argv[i] == '-') {
  141.             if (cl_find_string(argv[i], voptions, noptions) < noptions) {
  142.                 i += 2;    /* skip name and option */
  143.             } else {
  144.                 i += 1;    /* skip over switch name */
  145.             }
  146.         } else if (n == 1) {
  147.             return argv[i];
  148.         } else { /* skip over argument */
  149.             n--;
  150.             i++;
  151.         }
  152.     }
  153.     return NULL;
  154. }
  155.  
  156. /*****************************************************************************
  157. *            cl_init
  158. * Inputs:
  159. *    char *switches[]:    array of switch names
  160. *    int nsw:            number of switch names
  161. *    char *options[]:    array of option names
  162. *    int nopt:            number of option names
  163. *    char *av:            array of command line fields (argv)
  164. *    int ac:                number of command line fields (argc)
  165. * Returns:
  166. *    boolean: true if syntax checks OK, false otherwise
  167. * Effect:
  168. *    checks that all command line entries are valid
  169. *    saves info for use by other routines
  170. *****************************************************************************/
  171.  
  172. public boolean cl_init(switches, nsw, options, nopt, av, ac)
  173.     char *switches[];
  174.     int nsw;
  175.     char *options[];
  176.     int nopt;
  177.     char *av[];
  178.     int ac;
  179. {
  180.     int i;    /* index into argv */
  181.     boolean result = true;
  182.  
  183.     vswitches = switches;
  184.     nswitches = nsw;
  185.     voptions = options;
  186.     noptions = nopt;
  187.     argv = av;
  188.     argc = ac;
  189.  
  190.     for (i = 1; i < argc; i++) {  /* case fold lower */
  191.         int j;
  192.         for (j = 0; j < strlen(argv[i]); j++) {
  193.             argv[i][j] = tolower(argv[i][j]);
  194.         }
  195.     }
  196.  
  197.     /* check command line syntax: */
  198.     i = 1;
  199.     while (i < argc) {
  200.         if (*argv[i] == '-') {
  201.             if (cl_find_string(argv[i], voptions, noptions) < noptions) {
  202.                 i += 1; /* skip name and option */
  203.                 if (i < argc && *argv[i] == '-') {
  204.                     fprintf(stderr, "missing argument after %s\n", argv[i-1]);
  205.                     result = false;
  206.                     i += 1;
  207.                 }
  208.             } else if (cl_find_string(argv[i], vswitches, nswitches) < nswitches) {
  209.                 i += 1; /* skip over switch name */
  210.             } else {
  211.                 fprintf(stderr, "invalid switch: %s\n", argv[i]);
  212.                 i += 1;
  213.                 result = false;
  214.             }
  215.         } else i++; /* skip over argument */
  216.     }
  217.     cl_rdy = true;
  218.     return result;
  219. }
  220.  
  221. /*****************************************************************************
  222. *            cl_noption
  223. * Inputs:
  224. *    char *names[]: array of alternative switch names
  225. *    int nnames: number of alternative switch names
  226. * Result:
  227. *    char *: pointer to option if one exists, otherwise null
  228. * Effect:
  229. *    looks for pattern in command line of the form "-n s",
  230. *    where n is a member of names, and returns pointer to s
  231. * Implementation:
  232. *    find the option name, then see if the switch is followed by a
  233. *    string that does not start with "-"
  234. *****************************************************************************/
  235.  
  236. public char *cl_noption(names, nnames)
  237.     char *names[];
  238.     int nnames;
  239. {
  240.     int i;    /* index of switch */
  241.  
  242.     cl_ready_check();
  243.     cl_check_names(names, nnames, voptions, noptions);
  244.     i = cl_find_match(names, nnames) + 1; /* point at the option */
  245.     if (i < argc) { /* make sure option exists */
  246.         if (*(argv[i]) != '-') return argv[i];
  247.     }
  248.     return NULL;
  249. }
  250.  
  251. /*****************************************************************************
  252. *            cl_nswitch
  253. * Inputs:
  254. *    char *names[]: array of alternative switch names
  255. *    int nnames: number of alternative switch names
  256. * Result:
  257. *    char *: a pointer to command line switch if one exists,
  258. *            NULL otherwise
  259. * Effect:
  260. *    checks that names is valid
  261. *    finds a pattern in command line of the form "-n",
  262. *    where n is a member of names.
  263. *****************************************************************************/
  264.  
  265. public char *cl_nswitch(names, nnames)
  266.     char *names[];
  267.     int nnames;
  268. {
  269.     int i;    /* index of switch */
  270.  
  271.     cl_ready_check();
  272.     cl_check_names(names, nnames, vswitches, nswitches);
  273.     i = cl_find_match(names, nnames);
  274.     if (i < argc) {
  275.         return argv[i];
  276.     } else {
  277.         return NULL;
  278.     }
  279. }
  280.  
  281. /*****************************************************************************
  282. *            cl_option
  283. * Inputs:
  284. *    char *name:    option name
  285. * Returns:
  286. *    returns char *: the option string if found, otherwise null
  287. ****************************************************************/
  288.  
  289. public char *cl_option(name)
  290.     char *name;
  291. {
  292.     char *names[1];    /* array to hold name */
  293.  
  294.     names[0] = name;
  295.     return cl_noption(names, 1);
  296. }
  297.  
  298. /*****************************************************************************
  299. *            cl_switch
  300. * Inputs:
  301. *    char *name: switch name
  302. * Returns:
  303. *    boolean: true if switch found
  304. *****************************************************************************/
  305.  
  306. public boolean cl_switch(name)
  307.     char *name;
  308. {
  309.     char *names[1];    /* array to hold name */
  310.  
  311.     names[0] = name;
  312.     return cl_nswitch(names, 1) != NULL;
  313. }
  314.  
  315. /*****************************************************************************
  316. *            cl_find_match
  317. * Inputs:
  318. *    char *names[]: array of alternative switch or option names
  319. *    int nnames: number of alternative switch or option names
  320. * Effect:
  321. *    looks for command line switch that matches one of names
  322. * Returns:
  323. *    index of switch if found, argc if not found
  324. *****************************************************************************/
  325.  
  326. private int cl_find_match(names, nnames)
  327.     char *names[];
  328.     int nnames;
  329. {
  330.     int j;    /* loop counter */
  331.     for (j = 0; j < argc; j++) {
  332.         if (cl_find_string(argv[j], names, nnames) < nnames) return j;
  333.     }
  334.     return argc;
  335. }
  336.  
  337. /*****************************************************************************
  338. *            cl_find_string
  339. * Inputs:
  340. *    char *s:    string to find
  341. *    char *names[]:    array of strings
  342. *    int nnames:    number of strings
  343. * Effect:
  344. *    looks for s in names
  345. * Returns:
  346. *    index of s in names if found, nnames if not found
  347. *****************************************************************************/
  348.  
  349. private int cl_find_string(s, names, nnames)
  350.     char *s;
  351.     char *names[];
  352.     int nnames;
  353. {
  354.     int i; /* loop counter */
  355.     for (i = 0; i < nnames; i++) {
  356.         if (strcmp(s, names[i]) == 0) {
  357.             return i;
  358.         }
  359.     }
  360.     return nnames;
  361. }
  362.  
  363. /*****************************************************************************
  364. *            cl_ready_check
  365. * Effect:
  366. *    halt program if cl_rdy is not true.
  367. *****************************************************************************/
  368.  
  369. private void cl_ready_check()
  370. {
  371.     if (!cl_rdy) {
  372.         fprintf(stderr,
  373.             "Internal error: cl_init was not called, see cmdline.c\n");
  374.         exit(1);
  375.     }
  376. }
  377.